Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

nice_things/async/Future.sh

The Future class implements this popular synchronization primitive for asynchronous programming in pure POSIX sh. The API is inspired by libdex.

Futures—also called Promises in some programming languages—are eager. The async command starts executing from the moment the Future constructor is invoked.

Usage examples

dl_main=#{{{ new Future }}} -n 'main.host' curl https://main.host…
dl_mirror=#{{{ new Future }}} -n 'mirror.host' curl https://mirror.host…
download=#{{{ new Future }}} -n 'download' -o await_any -p "$dl_main" "$dl_mirror"
timeout=#{{{ new Future }}} -n 'timeout 60s' timeout 60

# Either timeout or get result of main/mirror request
if await_first winner "$download" "$timeout"; then
	# Futures do not propagate automatically, we must traverse manually to the inner Future
	await "$winner" "" dl_winner
	Future_get_name "$dl_winner" url
	log_debug "Finished downloading from '${url}'"
else
	Future_get_name "$winner" name
	log_error "Failed to download resource with '${name}' failure"
fi

# Destroy objects to free resources
for future in "$dl_main" "$dl_mirror" "$download" "$timeout"; do
	Future_destructor "$future"
done

await

Since 0.3.0 · Source

import "{ await }" from nice_things/async/Future_await.sh

Synopsis
await <&self> [<out_file>] [<out_var>]

Configuration

Description
Await the Future to settle. The returned status code is the status of the async command.

When the Future constructor is invoked with the -o option to capture the standard output of the async command, await offers two choices of output variables to get it:

  • <out_file> to get the path to the file containing the output.
  • <out_var> to get the contents of the output assigned to a variable.

Warning

Note that reading the file when assigning to <out_var> is done with the read builtin command in pure sh. No external utilities, like cat, are used. This means the assignment should be fast when the output is known to be small, but can get exponentially slower for larger outputs.

For this reason, the <out_var> parameter has limited usefulness to cases when the output of the command is known to be small. For all other cases, the <out_file> parameter should be preferred. Then, you can assign the contents of the file to a variable with the cat utility, if that is what you need.

Despite the unconventional shorter name, without the Future_ prefix, this implementation of await is an instance method of Future.

Options

Operands

  • <&self>: Self reference.
  • <out_file>: Output variable; the path to the output file will be written to this variable (if -o was specified in the Future constructor). Optional, or can be set to the null string to ignore when specifying <out_var>.
  • <out_var>: Output variable; the async command's output will be written to this variable (if -o was specified in the Future constructor). Optional.

Stdin

Stdout

Stderr

Exit status

  • 0: The async command completed successfully.
  • >0: The async command failed.
  • 12: Invalid self reference <&self> (abort).
  • 123: Unexpected error.

Abort
Aborts if self reference <&self> is invalid.

Usage examples

await "$future" output_file

await_all

Since 0.3.0 · Source

import "{ await_all }" from nice_things/async/Future_await_all.sh

Synopsis
await_all <&future>…

Configuration

Description
Await all <&future>s to settle. Return status code 0 if all succeeded, otherwise return the status code of the last failure.

Note that await_all always waits until all <&future>s have settled, even if there are early failures. If you want to return early on the first failure, consider the await_all_race function instead.

await_all is not a method, but a static function in the Future class. It can operate on many objects.

Options

Operands
<&future>: Reference to a Future object.

Stdin

Stdout

Stderr

Exit status

  • 0: All Futures completed successfully.
  • >0: Some Future failed.
  • 12: Invalid reference (abort).

Abort
Aborts if reference <&future> is invalid.

Usage examples

if await_all "$future1" "$future2" "$future3"; then
	log_debug "All futures succeeded!"
else
	log_warn "Some future failed!"
fi

await_all_race

Since 0.3.0 · Source

import "{ await_all_race }" from nice_things/async/Future_await_all_race.sh

Synopsis
await_all_race <&future>…

Configuration

Description
Await all <&future>s to settle. Return status code 0 if all succeeded, otherwise return the status code of the first failure.

Compared to await_all, which always runs through until all <&future>s have settled, await_all_race returns early on the first failure.

await_all_race is not a method, but a static function in the Future class. It can operate on many objects.

Options

Operands
<&future>: Reference to a Future object.

Stdin

Stdout

Stderr

Exit status

  • 0: All Futures completed successfully.
  • >0: Some Future failed.
  • 12: Invalid reference (abort).

Abort
Aborts if reference <&future> is invalid.

Usage examples

if await_all_race "$future1" "$future2" "$future3"; then
	log_debug "All futures succeeded!"
else
	log_warn "Some future failed!"
fi

await_any

Since 0.3.0 · Source

import "{ await_any }" from nice_things/async/Future_await_any.sh

Synopsis
await_any {-p | <out_var>} <&future>…

Configuration

Description
Await any <&future> to complete successfully. Return status code 0 if any succeeded, otherwise return status code 1 if all failed.

await_any races the <&future>s and returns as soon as one succeeds. A reference to the winning <&future> will be assigned to <out_var>, unless the -p option is specified, in which case the reference will be printed to stdout. It is mandatory to specify one of these two arguments, and they cannot be used together.

await_any is not a method, but a static function in the Future class. It can operate on many objects.

Options
-p: Print output instead of assigning to <out_var>.

Operands

  • <out_var>: Output variable; the result will be written to this variable. Skip when the -p option is specified. Or you can set this to the null string if you don't need a reference to the winning Future.
  • <&future>: Reference to a Future object.

Stdin

Stdout
If the -p option is specified, the result is printed to stdout. Otherwise, stdout is not used.

Stderr

Exit status

  • 0: Some Future completed successfully.
  • >0: All Futures failed.
  • 12: Invalid reference (abort).

Abort
Aborts if reference <&future> is invalid.

Usage examples

if await_any winner "$future1" "$future2" "$future3"; then
	log_debug "The winner is '${winner}'"
else
	log_warn "All futures failed!"
fi

await_first

Since 0.3.0 · Source

import "{ await_first }" from nice_things/async/Future_await_first.sh

Synopsis
await_first {-p | <out_var>} <&future>…

Configuration

Description
Await any <&future> to settle, no matter if it succeeded or failed. Return status code of the <&future> that settled first.

await_first races the <&future>s and returns as soon as one settles. A reference to the winning <&future> will be assigned to <out_var>, unless the -p option is specified, in which case the reference will be printed to stdout. It is mandatory to specify one of these two arguments, and they cannot be used together.

await_first is not a method, but a static function in the Future class. It can operate on many objects.

Options
-p: Print output instead of assigning to <out_var>.

Operands

  • <out_var>: Output variable; the result will be written to this variable. Skip when the -p option is specified. Or you can set this to the null string if you don't need a reference to the winning Future.
  • <&future>: Reference to a Future object.

Stdin

Stdout
If the -p option is specified, the result is printed to stdout. Otherwise, stdout is not used.

Stderr

Exit status

  • 0: The first Future to settle succeeded.
  • >0: The first Future to settle failed.
  • 12: Invalid reference (abort).

Abort
Aborts if reference <&future> is invalid.

Usage examples

if await_first winner "$future1" "$future2" "$future3"; then
	log_debug "The winner is '${winner}' and it succeeded"
else
	log_debug "The winner is '${winner}' and it failed"
fi

Future

Since 0.3.0 · Source

import "{ Future }" from nice_things/async/Future.sh

Synopsis
Future <&self> [-n <name>] [-o] [--] <command> [<arg>…]

Configuration

Description
Constructor for the Future class.

Usually, this constructor function should be invoked with the new macro, which takes care of creating the <&self> reference to the newly created object.

Options

  • -n <name>: Give a name to this object as a way of identifying it.
  • -o: Save the command's standard output to a file.
  • --: End of options.

Operands

  • <command>: The command to execute asynchronously.
  • <arg>: Optional argument to <command>.

Stdin

Stdout

Stderr

Exit status

  • 0: Successful completion.
  • 11: Invalid or missing arguments (abort).
  • 12: Invalid self reference <&self> (abort).
  • 123: Unexpected error (abort).

Abort

  • Aborts on invalid or missing arguments.
  • Aborts if self reference <&self> is invalid.
  • Aborts on unexpected error.

Usage examples

timer=#{{{ new Future }}} -n 'A 10 seconds timer' sleep 10

Future_destructor

Since 0.3.0 · Source

import "{ Future_destructor }" from nice_things/async/Future_destructor.sh

Synopsis
Future_destructor <&self>

Configuration

Description
Clear all data associated with the object.

If the Future has not settled yet, it will be cancelled, by sending a KILL signal to its process.

Options

Operands
<&self>: Self reference.

Stdin

Stdout

Stderr

Exit status

  • 0: Successful completion.
  • 12: Invalid self reference <&self> (abort).

Abort
Aborts if self reference <&self> is invalid.

Usage examples

Future_destructor "$future"

Future_get_name

Since 0.3.0 · Source

import "{ Future_get_name }" from nice_things/collections/Future_get_name.sh

Synopsis
Future_get_name <&self> <out_var>

Configuration

Description
Get name of the Future. A Future object only has a name if that was specified in the Future constructor using the -n <name> option.

Options

Operands

  • <&self>: Self reference.
  • <out_var>: Output variable; the result will be written to this variable.

Stdin

Stdout

Stderr

Exit status

  • 0: Successful completion.
  • 12: Invalid self reference <&self> (abort).

Abort
Aborts if self reference <&self> is invalid.

Usage examples

Future_get_name "$future" name

Future_is_settled

Since 0.3.0 · Source

import "{ Future_is_settled }" from nice_things/collections/Future_is_settled.sh

Synopsis
Future_is_settled <&self>

Configuration

Description
Test synchronously if the Future is already settled at the time of this method's invocation. Return status code 0 if true, 1 if false.

Options

Operands
<&self>: Self reference.

Stdin

Stdout

Stderr

Exit status

  • 0: The Future is already settled.
  • 1: The Future is not settled yet.
  • 12: Invalid self reference <&self> (abort).

Abort
Aborts if self reference <&self> is invalid.

Usage examples

if Future_is_settled "$future"; then
	log_debug "The future is already settled"
fi